<script setup lang="ts">
import { ref, onMounted, computed, onUnmounted, reactive } from 'vue';

interface Alarm {
  id: string;
  type: string;
  time: string;
  image: string;
  location: string;
  status: 'new' | 'processing' | 'resolved';
}

const alarms = ref<Alarm[]>([]);
const loading = ref(false); // Changed to false by default for background loading
const initialLoad = ref(true); // Track initial loading state
const error = ref<string | null>(null);
const searchQuery = ref('');
const statusFilter = ref<string | null>(null);
const pageInfo = ref({
  pageNum: 1,
  pageSize: 10,
  total: 0,
  totalPage: 0
});

// 图片查看器状态
const showImageViewer = ref(false);
const currentImage = ref('');
const currentImageTitle = ref('');

// 打开图片查看器
const openImageViewer = (image: string, title: string) => {
  currentImage.value = image;
  currentImageTitle.value = title;
  showImageViewer.value = true;
  document.body.style.overflow = 'hidden'; // 防止背景滚动
};

// 关闭图片查看器
const closeImageViewer = () => {
  showImageViewer.value = false;
  document.body.style.overflow = ''; // 恢复背景滚动
};

// 轮询间隔时间 (毫秒)
const POLLING_INTERVAL = 5000; // 改为5秒，更快地更新数据
let pollingTimer: number | null = null;

// 静默刷新状态
const silentRefresh = ref(false);

// 获取报警数据
const fetchAlarms = async (silent = false) => {
  // 只在初始加载或非静默刷新时显示加载状态
  if (!silent) {
    loading.value = true;
  }
  
  silentRefresh.value = silent;
  error.value = null;
  
  try {
    // 构建带有分页参数的URL
    const url = new URL('http://localhost:18081/oss/files');
    url.searchParams.append('pageNum', pageInfo.value.pageNum.toString());
    url.searchParams.append('pageSize', pageInfo.value.pageSize.toString());
    
    const response = await fetch(url.toString());
    
    if (!response.ok) {
      throw new Error(`API请求失败: ${response.status}`);
    }
    
    const responseData = await response.json();
    
    // 检查返回的数据结构是否符合预期
    if (responseData.code === 200 && responseData.data && responseData.data.list) {
      // 提取分页信息
      const { pageNum, pageSize, total, totalPage, list } = responseData.data;
      pageInfo.value = { pageNum, pageSize, total, totalPage };
      
      // 处理API返回的文件列表数据，将其映射为我们需要的报警格式
      const newAlarms = list.map((item: any) => {
        // 从文件名提取日期时间格式
        const timestamp = parseInt(item.name);
        const date = isNaN(timestamp) ? new Date() : new Date(timestamp);
        const formattedTime = date.toLocaleString();
        
        // 根据文件扩展名确定报警类型
        let alarmType = '火焰报警'; // 默认为火焰报警
        if (item.fileExtension === 'jpg' || item.fileExtension === 'jpeg' || item.fileExtension === 'png') {
          alarmType = '火焰报警';
        } else if (item.fileExtension === 'mp4' || item.fileExtension === 'avi') {
          alarmType = '视频报警';
        } else if (item.fileExtension === 'glb') {
          alarmType = '3D模型报警';
        } else if (item.fileExtension === 'zip') {
          alarmType = '压缩文件报警';
        }
        
        // 随机分配状态，实际项目中应从API获取
        const statuses = ['new', 'processing', 'resolved'];
        const randomStatus = statuses[Math.floor(Math.random() * statuses.length)] as 'new' | 'processing' | 'resolved';
        
        return {
          id: item.fileId,
          type: alarmType,
          time: formattedTime,
          image: item.url,
          location: item.note || '未知位置',
          status: randomStatus
        };
      });
      
      // 平滑更新数据，不会导致UI闪烁
      if (silent && alarms.value.length > 0) {
        // 检查是否有新数据
        const currentIds = new Set(alarms.value.map(alarm => alarm.id));
        const hasNewData = newAlarms.some((alarm: Alarm) => !currentIds.has(alarm.id));
        
        if (hasNewData) {
          // 平滑过渡到新数据
          setTimeout(() => {
            alarms.value = newAlarms;
          }, 300);
        } else {
          alarms.value = newAlarms;
        }
      } else {
        alarms.value = newAlarms;
      }
    } else {
      console.error('API返回的数据结构不符合预期:', responseData);
      throw new Error('API返回的数据结构不符合预期');
    }
  } catch (err) {
    console.error('获取报警数据失败:', err);
    
    // 只在非静默刷新时显示错误
    if (!silent) {
      error.value = err instanceof Error ? err.message : '获取报警数据失败';
    }
    
    // 如果API请求失败且没有现有数据，使用示例数据
    if (alarms.value.length === 0) {
      alarms.value = [
        {
          id: '1',
          type: '火焰报警',
          time: '2025-06-02 08:15:22',
          image: 'https://img.freepik.com/free-vector/realistic-fire-flames-light-background_1284-34772.jpg',
          location: '1号工厂区域A',
          status: 'new'
        },
        {
          id: '2',
          type: '入侵检测',
          time: '2025-06-02 07:30:45',
          image: 'https://img.freepik.com/free-vector/realistic-fire-alarm-design_23-2149061921.jpg',
          location: '仓库后门',
          status: 'processing'
        },
        {
          id: '3',
          type: '火焰报警',
          time: '2025-06-01 23:12:10',
          image: 'https://img.freepik.com/free-photo/fire-detection-system-concept-generative-ai_169016-30469.jpg',
          location: '厨房区域',
          status: 'resolved'
        },
        {
          id: '4',
          type: '异常行为',
          time: '2025-06-01 21:45:33',
          image: 'https://img.freepik.com/free-photo/security-camera-circuit-with-close-up-electrical-alarm-system_23-2150330829.jpg',
          location: '会议室C',
          status: 'new'
        },
        {
          id: '5',
          type: '设备故障',
          time: '2025-06-01 15:20:18',
          image: 'https://img.freepik.com/free-vector/realistic-security-camera-composition_1284-11744.jpg',
          location: '电力室',
          status: 'resolved'
        }
      ];
    }
  } finally {
    loading.value = false;
    initialLoad.value = false;
    silentRefresh.value = false;
  }
};

// 启动轮询
const startPolling = () => {
  if (pollingTimer) return; // 如果已经在轮询中，不再重复启动
  
  // 立即获取一次数据（首次加载显示加载状态）
  fetchAlarms(false);
  
  // 设置定时器进行轮询（后续刷新为静默）
  pollingTimer = window.setInterval(() => {
    fetchAlarms(true); // 静默刷新，不显示加载状态
  }, POLLING_INTERVAL);
};

// 停止轮询
const stopPolling = () => {
  if (pollingTimer) {
    window.clearInterval(pollingTimer);
    pollingTimer = null;
  }
};

// 过滤报警列表
const filteredAlarms = computed(() => {
  return alarms.value.filter(alarm => {
    // 搜索过滤
    const matchesSearch = searchQuery.value 
      ? alarm.type.toLowerCase().includes(searchQuery.value.toLowerCase()) || 
        alarm.location.toLowerCase().includes(searchQuery.value.toLowerCase())
      : true;
    
    // 状态过滤
    const matchesStatus = statusFilter.value 
      ? alarm.status === statusFilter.value
      : true;
    
    return matchesSearch && matchesStatus;
  });
});

// 设置状态过滤器
const setStatusFilter = (status: string | null) => {
  statusFilter.value = status;
};

// 获取状态对应的CSS类
const getStatusClass = (status: string) => {
  switch(status) {
    case 'new': return 'status-badge status-new';
    case 'processing': return 'status-badge status-processing';
    case 'resolved': return 'status-badge status-resolved';
    default: return 'status-badge';
  }
};

// 获取状态对应的文本
const getStatusText = (status: string) => {
  switch(status) {
    case 'new': return '新报警';
    case 'processing': return '处理中';
    case 'resolved': return '已解决';
    default: return '未知';
  }
};

// 处理图片加载错误
const handleImageError = (event: Event) => {
  const target = event.target as HTMLImageElement;
  if (target) {
    // 使用项目内的本地图片作为回退
    target.src = '/src/assets/image-error-placeholder.png';
    // 如果本地图片也加载失败，使用内联SVG图像
    target.onerror = () => {
      target.onerror = null; // 防止无限循环
      target.src = 'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(`
        <svg xmlns="http://www.w3.org/2000/svg" width="300" height="200" viewBox="0 0 300 200" fill="none">
          <rect width="300" height="200" fill="#f3f4f6"/>
          <path d="M150 80C141.716 80 135 86.7157 135 95C135 103.284 141.716 110 150 110C158.284 110 165 103.284 165 95C165 86.7157 158.284 80 150 80Z" fill="#9ca3af"/>
          <path d="M173 140H127L100 160V140H90C84.4772 140 80 135.523 80 130V70C80 64.4772 84.4772 60 90 60H210C215.523 60 220 64.4772 220 70V130C220 135.523 215.523 140 210 140H173Z" fill="#9ca3af"/>
        </svg>
      `);
    };
  }
};

// 组件挂载时启动轮询
onMounted(() => {
  startPolling();
});

// 组件卸载时停止轮询
onUnmounted(() => {
  stopPolling();
});

// 处理分页
const changePage = (newPage: number) => {
  pageInfo.value.pageNum = newPage;
  fetchAlarms(false); // 切换页面时显示加载状态
};

// 获取分页范围
const getPageRange = () => {
  const range = [];
  const start = Math.max(1, pageInfo.value.pageNum - 2);
  const end = Math.min(pageInfo.value.totalPage, pageInfo.value.pageNum + 2);
  for (let i = start; i <= end; i++) {
    range.push(i);
  }
  return range;
};

// 手动刷新数据（用户点击刷新按钮时）
const refreshData = () => {
  fetchAlarms(false); // 手动刷新时显示加载状态
};

// 处理刷新按钮点击
const handleRefreshClick = () => {
  refreshData();
};

// 处理重试按钮点击
const handleRetryClick = () => {
  fetchAlarms(false);
};
</script>

<template>
  <div class="alarm-list-container">
    <div class="alarm-header">
      <h1 class="apple-heading alarm-title">报警列表</h1>
      <button @click="handleRefreshClick" class="refresh-button">
        <svg xmlns="http://www.w3.org/2000/svg" class="refresh-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
        </svg>
        刷新
      </button>
    </div>
    
    <div class="filters-container">
      <div class="search-box">
        <input 
          v-model="searchQuery"
          type="text" 
          placeholder="搜索报警信息..." 
          class="search-input"
        />
        <svg xmlns="http://www.w3.org/2000/svg" class="search-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
        </svg>
      </div>
      
      <div class="filter-buttons">
        <button 
          @click="setStatusFilter(null)" 
          :class="['filter-button', !statusFilter ? 'active' : '']"
        >全部</button>
        <button 
          @click="setStatusFilter('new')" 
          :class="['filter-button filter-new', statusFilter === 'new' ? 'active' : '']"
        >新报警</button>
        <button 
          @click="setStatusFilter('processing')" 
          :class="['filter-button filter-processing', statusFilter === 'processing' ? 'active' : '']"
        >处理中</button>
        <button 
          @click="setStatusFilter('resolved')" 
          :class="['filter-button filter-resolved', statusFilter === 'resolved' ? 'active' : '']"
        >已解决</button>
      </div>
    </div>

    <!-- 加载状态 -->
    <div v-if="loading" class="loading-container">
      <div class="loading-spinner"></div>
    </div>

    <!-- 错误提示 -->
    <div v-else-if="error" class="error-message">
      <strong class="error-title">获取数据失败！</strong>
      <span class="error-text">{{ error }}</span>
      <button 
        @click="handleRetryClick" 
        class="retry-button"
      >
        重试
      </button>
    </div>
    
    <!-- 没有数据提示 -->
    <div v-else-if="filteredAlarms.length === 0" class="empty-state">
      <svg xmlns="http://www.w3.org/2000/svg" class="empty-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
      </svg>
      <p class="empty-text">没有找到符合条件的报警信息</p>
    </div>
    
    <!-- 报警列表 -->
    <div v-else class="alarms-grid">
      <div v-for="alarm in filteredAlarms" :key="alarm.id" class="apple-card alarm-card">
        <div class="alarm-card-content">
          <!-- 报警图片 -->
          <div class="alarm-image-container">
            <div class="alarm-image-wrapper" @click="openImageViewer(alarm.image, alarm.type)">
              <img 
                :src="alarm.image" 
                :alt="alarm.type"
                class="alarm-image"
                @error="handleImageError"
                loading="lazy"
              />
              <div class="image-overlay">
                <svg xmlns="http://www.w3.org/2000/svg" class="zoom-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0zM10 7v3m0 0v3m0-3h3m-3 0H7" />
                </svg>
              </div>
            </div>
            <div class="status-badge-container">
              <span :class="getStatusClass(alarm.status)">
                {{ getStatusText(alarm.status) }}
              </span>
            </div>
          </div>
          
          <!-- 报警详情 -->
          <div class="alarm-details">
            <div class="alarm-type">{{ alarm.type }}</div>
            
            <div class="alarm-info">
              <div class="alarm-id-text">ID: {{ alarm.id }}</div>
              
              <div class="alarm-time">
                <svg xmlns="http://www.w3.org/2000/svg" class="info-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
                </svg>
                <span class="apple-text">{{ alarm.time }}</span>
              </div>
              
              <div class="alarm-location">
                <svg xmlns="http://www.w3.org/2000/svg" class="info-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
                  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
                </svg>
                <span class="apple-text">{{ alarm.location }}</span>
              </div>
            </div>
            
            <div class="alarm-actions">
              <button class="action-button details-button">查看详情</button>
              <button v-if="alarm.status !== 'resolved'" class="action-button process-button">处理报警</button>
            </div>
          </div>
        </div>
      </div>
    </div>
    
    <!-- 分页控件 -->
    <div v-if="filteredAlarms.length > 0" class="pagination">
      <button 
        class="pagination-button" 
        :disabled="pageInfo.pageNum <= 1"
        @click="changePage(pageInfo.pageNum - 1)"
      >
        <svg xmlns="http://www.w3.org/2000/svg" class="pagination-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
        </svg>
      </button>
      
      <!-- 如果总页数太多，只显示部分页码 -->
      <template v-if="pageInfo.totalPage <= 5">
        <button 
          v-for="page in pageInfo.totalPage" 
          :key="page" 
          class="pagination-button" 
          :class="{ 'active': page === pageInfo.pageNum }"
          @click="changePage(page)"
        >
          {{ page }}
        </button>
      </template>
      
      <template v-else>
        <!-- 始终显示第一页 -->
        <button 
          class="pagination-button" 
          :class="{ 'active': 1 === pageInfo.pageNum }"
          @click="changePage(1)"
        >
          1
        </button>
        
        <!-- 如果当前页不靠近第一页，显示省略号 -->
        <span v-if="pageInfo.pageNum > 3" class="pagination-ellipsis">...</span>
        
        <!-- 显示当前页附近的页码 -->
        <button 
          v-for="page in getPageRange()" 
          :key="page" 
          class="pagination-button" 
          :class="{ 'active': page === pageInfo.pageNum }"
          @click="changePage(page)"
        >
          {{ page }}
        </button>
        
        <!-- 如果当前页不靠近最后一页，显示省略号 -->
        <span v-if="pageInfo.pageNum < pageInfo.totalPage - 2" class="pagination-ellipsis">...</span>
        
        <!-- 始终显示最后一页 -->
        <button 
          v-if="pageInfo.totalPage > 1"
          class="pagination-button" 
          :class="{ 'active': pageInfo.totalPage === pageInfo.pageNum }"
          @click="changePage(pageInfo.totalPage)"
        >
          {{ pageInfo.totalPage }}
        </button>
      </template>
      
      <button 
        class="pagination-button" 
        :disabled="pageInfo.pageNum >= pageInfo.totalPage"
        @click="changePage(pageInfo.pageNum + 1)"
      >
        <svg xmlns="http://www.w3.org/2000/svg" class="pagination-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
        </svg>
      </button>
    </div>

    <!-- 图片查看器模态框 -->
    <div v-if="showImageViewer" class="image-viewer-overlay" @click="closeImageViewer">
      <div class="image-viewer-container" @click.stop>
        <div class="image-viewer-header">
          <h3 class="image-viewer-title">{{ currentImageTitle }}</h3>
          <button class="close-button" @click="closeImageViewer">
            <svg xmlns="http://www.w3.org/2000/svg" class="close-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
            </svg>
          </button>
        </div>
        <div class="image-viewer-content">
          <img :src="currentImage" class="full-image" @error="handleImageError" loading="lazy" />
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.alarm-list-container {
  width: 100%;
  max-width: 100%;
  margin: 0 auto;
  padding: 0.5rem;
  box-sizing: border-box;
  overflow-x: hidden;
}

.alarm-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1.5rem;
  background: rgba(255, 255, 255, 0.7);
  padding: 1rem;
  border-radius: 10px;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
  border: 1px solid rgba(0, 122, 255, 0.1);
}

.alarm-title {
  margin-bottom: 0;
  font-size: 1.5rem;
  font-weight: 700;
  background: linear-gradient(90deg, #1a1e2d, #2c3e50);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  position: relative;
}

.refresh-button {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.5rem 1.25rem;
  background: linear-gradient(135deg, var(--color-primary), var(--color-primary-dark));
  color: white;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.2s ease;
  box-shadow: 0 4px 10px rgba(0, 113, 227, 0.3);
  font-weight: 500;
}

.refresh-button:hover {
  background: linear-gradient(135deg, var(--color-primary-dark), var(--color-primary));
  transform: translateY(-2px);
  box-shadow: 0 6px 15px rgba(0, 113, 227, 0.4);
}

.refresh-button:active {
  transform: translateY(0);
  box-shadow: 0 2px 5px rgba(0, 113, 227, 0.3);
}

.refresh-icon {
  width: 1.25rem;
  height: 1.25rem;
}

.filters-container {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  margin-bottom: 1.5rem;
  justify-content: space-between;
  background: rgba(255, 255, 255, 0.7);
  padding: 1rem;
  border-radius: 10px;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
  border: 1px solid rgba(0, 122, 255, 0.1);
}

.search-box {
  position: relative;
  flex-grow: 0;
  width: 300px;
  max-width: 100%;
}

@media (max-width: 768px) {
  .search-box {
    width: 100%;
    margin-bottom: 0.75rem;
  }
  
  .filters-container {
    flex-direction: column;
    align-items: flex-start;
  }
  
  .filter-buttons {
    width: 100%;
    justify-content: space-between;
  }
}

.search-input {
  width: 100%;
  padding-left: 2.5rem;
  padding-right: 1rem;
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
  border-radius: 8px;
  border: 1px solid rgba(0, 122, 255, 0.2);
  background-color: rgba(255, 255, 255, 0.8);
  transition: all 0.3s ease;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
}

.search-input:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px rgba(0, 113, 227, 0.2);
  background-color: white;
}

.search-icon {
  position: absolute;
  left: 0.75rem;
  top: 50%;
  transform: translateY(-50%);
  height: 1.25rem;
  width: 1.25rem;
  color: var(--color-primary);
}

.filter-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.filter-button {
  padding: 0.5rem 1rem;
  border-radius: 8px;
  background-color: rgba(255, 255, 255, 0.8);
  color: #4b5563;
  transition: all 0.3s ease;
  border: 1px solid rgba(0, 0, 0, 0.05);
  cursor: pointer;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
  font-weight: 500;
}

.filter-button:hover {
  background-color: rgba(255, 255, 255, 1);
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  transform: translateY(-1px);
}

.filter-button.active {
  background: linear-gradient(135deg, var(--color-primary), var(--color-primary-dark));
  color: white;
  border: none;
  box-shadow: 0 4px 10px rgba(0, 113, 227, 0.3);
}

.filter-new {
  background-color: rgba(255, 59, 48, 0.1);
  color: var(--color-danger-dark);
}

.filter-new:hover {
  background-color: rgba(255, 59, 48, 0.2);
}

.filter-new.active {
  background: linear-gradient(135deg, var(--color-danger), var(--color-danger-dark));
  color: white;
  box-shadow: 0 4px 10px rgba(255, 59, 48, 0.3);
}

.filter-processing {
  background-color: rgba(255, 149, 0, 0.1);
  color: var(--color-warning-dark);
}

.filter-processing:hover {
  background-color: rgba(255, 149, 0, 0.2);
}

.filter-processing.active {
  background: linear-gradient(135deg, var(--color-warning), var(--color-warning-dark));
  color: white;
  box-shadow: 0 4px 10px rgba(255, 149, 0, 0.3);
}

.filter-resolved {
  background-color: rgba(52, 199, 89, 0.1);
  color: var(--color-success-dark);
}

.filter-resolved:hover {
  background-color: rgba(52, 199, 89, 0.2);
}

.filter-resolved.active {
  background: linear-gradient(135deg, var(--color-success), var(--color-success-dark));
  color: white;
  box-shadow: 0 4px 10px rgba(52, 199, 89, 0.3);
}

.alarms-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1.25rem;
  width: 100%;
  margin: 0 auto;
  box-sizing: border-box;
}

.apple-card {
  margin-bottom: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  transition: all 0.3s ease;
  position: relative;
  overflow: hidden;
  border: none;
}

.apple-card:before {
  content: '';
  position: absolute;
  top: -2px;
  left: -2px;
  right: -2px;
  height: 2px;
  background: linear-gradient(90deg, var(--tech-accent-blue), var(--tech-accent-cyan));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.3s ease;
}

.apple-card:hover:before {
  transform: scaleX(1);
}

.alarm-card-content {
  display: flex;
  flex-direction: column;
  height: 100%;
  width: 100%;
}

.alarm-image-container {
  position: relative;
  width: 100%;
  overflow: hidden;
}

.alarm-image-wrapper {
  aspect-ratio: 4 / 3;
  background-color: #f3f4f6;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='200' viewBox='0 0 300 200' fill='none'%3E%3Crect width='300' height='200' fill='%23f3f4f6'/%3E%3C/svg%3E");
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: auto;
  position: relative;
  cursor: pointer;
}

.alarm-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.5s ease;
}

.apple-card:hover .alarm-image {
  transform: scale(1.05);
}

.image-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 60%);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.alarm-image-wrapper:hover .image-overlay {
  opacity: 1;
}

.zoom-icon {
  width: 3rem;
  height: 3rem;
  color: white;
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3));
  transition: transform 0.3s ease;
}

.alarm-image-wrapper:hover .zoom-icon {
  transform: scale(1.1);
}

.status-badge-container {
  position: absolute;
  top: 0.75rem;
  left: 0.75rem;
  z-index: 2;
}

.status-badge {
  padding: 0.25rem 0.75rem;
  border-radius: 6px;
  font-size: 0.75rem;
  font-weight: 500;
  color: white;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
  display: inline-flex;
  align-items: center;
  letter-spacing: 0.02em;
}

.status-badge:before {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  margin-right: 6px;
  background-color: rgba(255, 255, 255, 0.8);
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.3);
}

.status-new {
  background: linear-gradient(135deg, #ff3b30, #ff453a);
}

.status-processing {
  background: linear-gradient(135deg, #ff9500, #ff9f0a);
}

.status-resolved {
  background: linear-gradient(135deg, #34c759, #30d158);
}

.alarm-details {
  padding: 1rem;
  width: 100%;
  display: flex;
  flex-direction: column;
  flex-grow: 1;
  background: rgba(255, 255, 255, 0.95);
}

.alarm-type {
  font-size: 1.1rem;
  font-weight: 600;
  color: #1d1d1f;
  margin-bottom: 0.5rem;
  letter-spacing: -0.01em;
}

.alarm-id-text {
  font-size: 0.7rem;
  color: #9ca3af;
  margin-bottom: 0.5rem;
  font-family: monospace;
}

.alarm-info {
  margin-bottom: 0.75rem;
  flex-grow: 1;
}

.alarm-time, .alarm-location {
  display: flex;
  align-items: center;
  margin-bottom: 0.35rem;
  font-size: 0.75rem;
}

.info-icon {
  height: 1rem;
  width: 1rem;
  color: var(--color-primary);
  margin-right: 0.5rem;
  flex-shrink: 0;
}

.apple-text {
  color: #6b7280;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.alarm-actions {
  display: flex;
  justify-content: space-between;
  gap: 0.5rem;
  margin-top: auto;
}

.action-button {
  padding: 0.35rem 0.75rem;
  border-radius: 6px;
  transition: all 0.3s ease;
  border: none;
  cursor: pointer;
  font-size: 0.75rem;
  flex: 1;
  text-align: center;
  font-weight: 500;
}

.details-button {
  background-color: rgba(0, 113, 227, 0.1);
  color: var(--color-primary);
  border: 1px solid rgba(0, 113, 227, 0.2);
}

.details-button:hover {
  background-color: rgba(0, 113, 227, 0.2);
  box-shadow: 0 2px 5px rgba(0, 113, 227, 0.2);
  transform: translateY(-1px);
}

.process-button {
  background: linear-gradient(135deg, var(--color-primary), var(--color-primary-dark));
  color: white;
  box-shadow: 0 2px 5px rgba(0, 113, 227, 0.2);
}

.process-button:hover {
  box-shadow: 0 4px 8px rgba(0, 113, 227, 0.3);
  transform: translateY(-1px);
}

.pagination {
  display: flex;
  justify-content: center;
  margin-top: 2.5rem;
  margin-bottom: 1.5rem;
  gap: 0.25rem;
}

.pagination-button {
  padding: 0.35rem 0.85rem;
  border-radius: 6px;
  background-color: rgba(255, 255, 255, 0.8);
  transition: all 0.3s ease;
  border: 1px solid rgba(0, 0, 0, 0.05);
  cursor: pointer;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
}

.pagination-button:hover:not(:disabled) {
  background-color: white;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  transform: translateY(-1px);
}

.pagination-button.active {
  background: linear-gradient(135deg, var(--color-primary), var(--color-primary-dark));
  color: white;
  border: none;
  box-shadow: 0 4px 10px rgba(0, 113, 227, 0.3);
}

.pagination-button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.pagination-icon {
  height: 1.25rem;
  width: 1.25rem;
}

.pagination-ellipsis {
  padding: 0 0.5rem;
  color: #6b7280;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Image viewer styles */
.image-viewer-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.85);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

.image-viewer-container {
  width: 90%;
  max-width: 1200px;
  max-height: 90vh;
  background-color: rgba(255, 255, 255, 0.95);
  border-radius: 12px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: 0 25px 50px rgba(0, 0, 0, 0.25);
  animation: modal-in 0.3s ease-out;
}

@keyframes modal-in {
  from {
    opacity: 0;
    transform: scale(0.95);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

.image-viewer-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1.25rem;
  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
  background: linear-gradient(135deg, var(--tech-gradient-start), var(--tech-gradient-end));
  color: white;
}

.image-viewer-title {
  margin: 0;
  font-size: 1.25rem;
  color: white;
  font-weight: 500;
}

.close-button {
  background: rgba(255, 255, 255, 0.2);
  border: none;
  cursor: pointer;
  width: 2.5rem;
  height: 2.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  transition: all 0.2s ease;
}

.close-button:hover {
  background: rgba(255, 255, 255, 0.3);
  transform: rotate(90deg);
}

.close-icon {
  width: 1.5rem;
  height: 1.5rem;
  color: white;
}

.image-viewer-content {
  padding: 1.5rem;
  overflow: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-grow: 1;
  max-height: calc(90vh - 5rem);
  background: rgba(0, 0, 0, 0.03);
}

.full-image {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
  border-radius: 4px;
}

.loading-container {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 2.5rem 0;
}

.loading-spinner {
  height: 2.5rem;
  width: 2.5rem;
  border-radius: 9999px;
  border: 2px solid transparent;
  border-bottom-color: var(--color-primary);
  animation: spin 1s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.error-message {
  background-color: rgba(255, 59, 48, 0.1);
  border: 1px solid var(--color-danger);
  color: var(--color-danger-dark);
  padding: 1rem;
  border-radius: 10px;
  position: relative;
  margin-bottom: 1.5rem;
  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
}

.error-title {
  font-weight: 700;
}

.error-text {
  display: block;
  margin-top: 0.5rem;
}

.retry-button {
  margin-top: 0.75rem;
  padding: 0.5rem 1rem;
  background: linear-gradient(135deg, var(--color-danger), var(--color-danger-dark));
  color: white;
  border-radius: 6px;
  border: none;
  cursor: pointer;
  transition: all 0.3s ease;
  box-shadow: 0 2px 8px rgba(255, 59, 48, 0.3);
}

.retry-button:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(255, 59, 48, 0.4);
}

.empty-state {
  text-align: center;
  padding: 2rem 0;
  background: rgba(255, 255, 255, 0.7);
  border-radius: 10px;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
  border: 1px solid rgba(0, 122, 255, 0.1);
}

.empty-icon {
  height: 2.5rem;
  width: 2.5rem;
  color: #9ca3af;
  margin: 0 auto 1rem auto;
  opacity: 0.7;
}

.empty-text {
  color: #6b7280;
  font-size: 1rem;
  margin: 0;
}
</style> 